package logica;

import uniandes.cupi2.collections.arbol.arbolBinario.ArbolBinario;
import uniandes.cupi2.collections.arbol.arbolBinario.NodoArbolBinario;
import uniandes.cupi2.collections.iterador.Iterador;

import java.io.*;
import java.util.ArrayList;

public class solucionador {

	private ArbolBinario<String>  arbol ;      
	private String linea;
	private ArrayList<String> operadoresBinarios;
	private ArrayList<String> operadoresUnarios;
	private Transformaciones rTransformaciones;
	private File fichero;
	private PrintWriter pw;
	private String variableDespejar;
	private int id;



	public  solucionador (){
		arbol = new ArbolBinario<String>();
		linea = new String();
		id=0;
		rTransformaciones = new Transformaciones();
		operadoresBinarios= rTransformaciones.getOperadoresBinarios();
		operadoresUnarios= rTransformaciones.getOperadoresUnarios();
		try {
			fichero = new File("./GP_15_01.txt");
			pw = new PrintWriter(fichero);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (null != fichero)
				{
					
				}
			} catch (Exception e2) {
				e2.printStackTrace();
			}
		}
	}

	/**
	 * 
	 */
	public void cargarArchivo(){
		//equ.in
		File archivo = null;
		FileReader fr = null;
		BufferedReader br = null;

		try {
			// Apertura del fichero y creacion de BufferedReader para poder
			// hacer una lectura comoda (disponer del metodo readLine()).
			archivo = new File ("./prueba.txt");
			fr = new FileReader (archivo);
			br = new BufferedReader(fr);

			// Lectura del fichero
			pw.println(br.readLine());
			linea=br.readLine();	
			variableDespejar=br.readLine();
		}
		catch(Exception e){
			e.printStackTrace();
		}finally{
			try{                    
				if( null != fr ){   
					fr.close();     
				}                  
			}catch (Exception e2){ 
				e2.printStackTrace();
			}
		}
	}

	/**
	 * 
	 */
	public void cargarArbol(){

		String [] arreglo= new String[linea.length()]; 
		NodoArbolBinario<String> raiz = new NodoArbolBinario<String>(linea.charAt(linea.length()-1)+"");
		arbol.definirRaiz(raiz);
		arreglo = linea.split(" ");
		int esperados =0;
		String primero=arreglo[arreglo.length-2];
		int j=0;

		if (operadoresBinarios.contains(primero)){
			esperados=+2;
		}
		else if (operadoresUnarios.contains(primero)){
			esperados=+1;
		}
		else{ // Constante
			j=arreglo.length-2;

		}

		for (int i =arreglo.length-3;i>=0 && esperados!=0;i--)
		{
			String actual=arreglo[i];
			if (operadoresBinarios.contains(actual)){
				esperados++;
			}
			else if (!operadoresUnarios.contains(actual) ){
				esperados--;
			}
			j=i;
		}

		ArrayList<String> derechos = new ArrayList<String>();
		ArrayList<String> izquierdos = new ArrayList<String>();

		for (int i =0; i<j;i++)
		{
			izquierdos.add(arreglo[i]);
		}

		for (int i =j; i<=arreglo.length-2;i++)
		{
			derechos.add(arreglo[i]);
		}

		NodoArbolBinario<String> izq = new NodoArbolBinario<String>(izquierdos.get(izquierdos.size()-1));
		NodoArbolBinario<String> der = new NodoArbolBinario<String>(derechos.get(derechos.size()-1));
		raiz.encadenarIzquierdo(izq);
		raiz.encadenarDerecho(der);
		llenarDerecho(derechos, der);
		llenarIzquierdo(izquierdos, izq);
	}

	public void llenarDerecho(ArrayList<String> der, NodoArbolBinario<String> raiz){
		int i =der.size()-1;
		ArrayList<NodoArbolBinario<String>> pendientes = new ArrayList<NodoArbolBinario<String>>();
		ArrayList<Integer> posPendientes = new ArrayList<Integer>();
		if(i==0){
			//Ignora el paso
		}
		else{
			while(i > 0)
			{		
				String actual = raiz.darElemento();
				if(operadoresUnarios.contains(actual)){
					i--;
					NodoArbolBinario<String> hijo = new NodoArbolBinario<String>(der.get(i));
					raiz.encadenarDerecho(hijo);
					raiz = hijo;
				}
				else if(operadoresBinarios.contains(actual)&& operadoresUnarios.contains(der.get(i-1)))
				{
					i--;
					NodoArbolBinario<String> hijo = new NodoArbolBinario<String>(der.get(i));
					raiz.encadenarDerecho(hijo);
					pendientes.add(raiz);
					raiz = hijo;
				}
				else if(!operadoresBinarios.contains(actual)&&!operadoresUnarios.contains(actual)){
					i--;
					NodoArbolBinario<String> t = pendientes.get(pendientes.size() - 1);
					pendientes.remove(t);
					NodoArbolBinario<String> hijo = new NodoArbolBinario<String>(der.get(i));
					t.encadenarIzquierdo(hijo);
					raiz=hijo;
				}

				else if(operadoresBinarios.contains(actual)&&!operadoresUnarios.contains(actual)){
					i--;
					NodoArbolBinario<String> hijo = new NodoArbolBinario<String>(der.get(i));
					raiz.encadenarDerecho(hijo);
					pendientes.add(raiz);
					posPendientes.add(i - 1);
					raiz = hijo;
				}
				if(i==0)
				{
					break;
				}
			}
		}
	}

	public void llenarIzquierdo(ArrayList<String> izq, NodoArbolBinario<String> raiz){
		int i =izq.size()-1;
		ArrayList<NodoArbolBinario<String>> pendientes = new ArrayList<NodoArbolBinario<String>>();
		ArrayList<Integer> posPendientes = new ArrayList<Integer>();
		if(i==0){
			//Ignora el paso
		}
		else{
			while(i > 0)
			{		
				String actual = raiz.darElemento();
				if(operadoresUnarios.contains(actual)){
					i--;
					NodoArbolBinario<String> hijo = new NodoArbolBinario<String>(izq.get(i));
					raiz.encadenarDerecho(hijo);
					raiz = hijo;
				}
				else if(operadoresBinarios.contains(actual)&& operadoresUnarios.contains(izq.get(i-1)))
				{
					i--;
					NodoArbolBinario<String> hijo = new NodoArbolBinario<String>(izq.get(i));
					raiz.encadenarDerecho(hijo);
					pendientes.add(raiz);
					raiz = hijo;
				}
				else if(!operadoresBinarios.contains(actual)&&!operadoresUnarios.contains(actual)){
					i--;
					NodoArbolBinario<String> t = pendientes.get(pendientes.size() - 1);
					pendientes.remove(t);
					NodoArbolBinario<String> hijo = new NodoArbolBinario<String>(izq.get(i));
					t.encadenarIzquierdo(hijo);
					raiz=hijo;
				}

				else if(operadoresBinarios.contains(actual)&&!operadoresUnarios.contains(actual)){
					i--;
					NodoArbolBinario<String> hijo = new NodoArbolBinario<String>(izq.get(i));
					raiz.encadenarDerecho(hijo);
					pendientes.add(raiz);
					posPendientes.add(i - 1);
					raiz = hijo;
				}
				if(i==0)
				{
					break;
				}
			}
		}
	}
	public void operador (String op, NodoArbolBinario<String> raiz, String variable){
		if (op.equals("log")){
			rTransformaciones.tAislamientoLog(raiz,pw);
			imprimirRespuesta();
		}
		else if (op.equals("2^")){
			rTransformaciones.tAislamientoLogInv(raiz,pw);
			imprimirRespuesta();
		}
		else if (op.equals("rz")){
			rTransformaciones.tAislamientoRaiz(raiz,pw);
			imprimirRespuesta();
		}
		else if (op.equals("^2")){
			rTransformaciones.tAislamientoRaizInv(raiz,pw);
			imprimirRespuesta();
		}
		else if (op.equals("+")){
			rTransformaciones.tAislamientoSuma(raiz, variable,pw);
			imprimirRespuesta();
		}
		else if (op.equals("-")){
			rTransformaciones.tAislamientoResta(raiz, variable,pw);
			imprimirRespuesta();
		}
		else if (op.equals("*")){
			rTransformaciones.tAislamientoMultiplicacion(raiz, variable,pw);
			imprimirRespuesta();
		}
		else{
			rTransformaciones.tAislamientoDivision(raiz, variable,pw);
			imprimirRespuesta();
		}
	}

	public void solucionarEcuacion(){
		System.out.println("sol");
		imprimirRespuesta();
		NodoArbolBinario<String> hijoDer=arbol.darRaiz().darDerecho();
		NodoArbolBinario<String> hijoIzq=arbol.darRaiz().darIzquierdo();
		String reDer = hijoDer.buscar(variableDespejar);
		String reIzq = hijoIzq.buscar(variableDespejar);

		if(!(reDer==null)&& !(reIzq==null)){

		}
		else {
			String temp=hijoDer.buscar(variableDespejar);

			if ( !(temp==null)){
				while (!hijoDer.darElemento().equals(variableDespejar)){
					String elemento = hijoDer.darElemento();
					operador(elemento, arbol.darRaiz(), variableDespejar);
					hijoDer = arbol.darRaiz().darDerecho();
					hijoIzq = arbol.darRaiz().darIzquierdo();
				}
			}
			else{
				while (!hijoIzq.darElemento().equals(variableDespejar)){
					String elemento = hijoIzq.darElemento();
					operador(elemento, arbol.darRaiz(), variableDespejar);
					hijoDer = arbol.darRaiz().darDerecho();
					hijoIzq = arbol.darRaiz().darIzquierdo();
				}
			}
		}
		pw.close();
	}

	public void imprimirRespuesta(){
		try
		{
			String linea = "[" + id + "] ";
			id++;
			Iterador<String> ino = arbol.darInorden();
			while(ino.haySiguiente()){
				String actual = ino.darSiguiente();
				linea += actual;
			}
			pw.println(linea);
			System.out.println(linea);
		} 
		catch (Exception e)
		{
			e.printStackTrace();
		} 
		finally 
		{
			try 
			{
				if (null != fichero)
				{

				}
			} 
			catch (Exception e2) 
			{
				e2.printStackTrace();
			}
		}
	}
	public void prueba (){
		NodoArbolBinario<String> hijoIzq=arbol.darRaiz().darIzquierdo();
		rTransformaciones.coleccionDiferenciaCuadrados(hijoIzq, variableDespejar, pw);
		imprimirRespuesta();
	}

	public static void main(String[] args) {
		solucionador y = new solucionador();
		y.cargarArchivo();
		y.cargarArbol();
		//y.solucionarEcuacion();
		y.prueba();
	}
}
